package cc.rengu.igas.cops.core.service.trans.unionpay;

import cc.rengu.igas.channel.upqc.facade.bean.CouponInfoBean;
import cc.rengu.igas.channel.upqc.facade.bean.PayeeInfoBean;
import cc.rengu.igas.channel.upqc.facade.bean.PayerInfo;
import cc.rengu.igas.channel.upqc.facade.bean.RiskInfoBean;
import cc.rengu.igas.channel.upqc.facade.request.B2COrderPayRequest;
import cc.rengu.igas.channel.upqc.facade.request.B2CQueryCouponRequest;
import cc.rengu.igas.channel.upqc.facade.response.B2COrderPayResponse;
import cc.rengu.igas.channel.upqc.facade.response.B2CQueryCouponResponse;
import cc.rengu.igas.channel.upqc.facade.result.Result;
import cc.rengu.igas.cops.common.constant.CopsParamConstant;
import cc.rengu.igas.cops.common.enums.RespCodeEnum;
import cc.rengu.igas.cops.common.enums.SignTokenTypeEnum;
import cc.rengu.igas.cops.core.model.SignCardInfoBean;
import cc.rengu.igas.cops.core.realize.PublicDealService;
import cc.rengu.igas.cops.core.realize.SignCardInfoService;
import cc.rengu.igas.cops.core.realize.impl.PublicDealServiceImpl;
import cc.rengu.igas.cops.core.realize.impl.SignCardInfoServiceImpl;
import cc.rengu.igas.cops.facade.bean.CouponInfo;
import cc.rengu.igas.cops.facade.bean.RiskInfo;
import cc.rengu.igas.cops.facade.request.BankB2cNewUserSignPayRequest;
import cc.rengu.igas.cops.facade.response.BankB2cNewUserSignPayResponse;
import cc.rengu.igas.share.common.enums.UserPayAuthTypeEnum;
import cc.rengu.igas.share.core.model.UserInfo;
import cc.rengu.igas.share.core.realize.UserService;
import cc.rengu.igas.share.core.realize.impl.UserServiceImpl;
import cc.rengu.oltp.service.base.BizBaseService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.SignAcctInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.SignAcctInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.SignAcctInfo;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.common.entity.UserOrderInfo;
import cc.rengu.oltp.service.common.enums.*;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.model.OrderInfo;
import cc.rengu.oltp.service.model.RiskMonitorInfo;
import cc.rengu.oltp.service.realize.*;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.OrderServiceImpl;
import cc.rengu.oltp.service.realize.impl.SmsServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/*
 * 主扫他行码：新用户签约&新卡绑定并支付
 *
 *
 *  Create by pankey on 2020-9-16
 */
public class BankB2cNewUserSignPayService extends BizBaseService implements TransCustomImpl {

    @Override
    protected Object beforeBizProcess() throws Exception {
        BankB2cNewUserSignPayRequest bankB2cNewUserSignPayRequest = new BankB2cNewUserSignPayRequest();
        ConvertUtil.convertOutput(bankB2cNewUserSignPayRequest);
        String orderAmt = AmountUtil.checkAmt(bankB2cNewUserSignPayRequest.getOrderAmt(), 2, false);
        bankB2cNewUserSignPayRequest.setOrderAmt(orderAmt);
        return bankB2cNewUserSignPayRequest;
    }

    @Override
    protected BizResponse callBizService(Object request) throws Exception {

        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String msgSrcId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID);
        BankB2cNewUserSignPayRequest bankB2cNewUserSignPayRequest = (BankB2cNewUserSignPayRequest) request;
        String instId = bankB2cNewUserSignPayRequest.getHeader().getInstId();
        String chanId = bankB2cNewUserSignPayRequest.getOrderChanlId();
        /* 用户会话校验 */
        UserService userService = new UserServiceImpl();
        UserInfo userInfo = JSON.parseObject(RedisUtil.hashGet(bankB2cNewUserSignPayRequest.getHeader().getSession(), bankB2cNewUserSignPayRequest.getHeader().getInstId() + bankB2cNewUserSignPayRequest.getUserId()), UserInfo.class);
        if (null == userInfo) {
            rglog.error("获取用户信息失败!");
        }
        /*手机银行扫他行二维码不关注上送商户号*/
        /*校验卡类型，获得签约时需要的数据*/
        SignCardInfoService cardBinCheckService = new SignCardInfoServiceImpl();
        SignCardInfoBean signCardInfo = cardBinCheckService.getSignCardInfo(bankB2cNewUserSignPayRequest.getHeader().getInstId(),
                bankB2cNewUserSignPayRequest.getAcctNo(),
                bankB2cNewUserSignPayRequest.getSignTokenType());

        userInfo = new UserInfo();
        boolean isExitUser = false;
        if (userInfo == null) {
            rglog.debug("创建用户....");
            String sysSeqNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM);
            String seqUserId = instId + DateUtil.getCurrentDate() + sysSeqNum.substring(sysSeqNum.length() - 8);
            userInfo.setUserInst(userInfo.getUserInst());
            userInfo.setUserId(seqUserId);
            //用户加密盐生成规则：当前机构号+8位日期+8为序列号
            userInfo.setTransPasswordSalt(seqUserId);
            userInfo.setUserName(bankB2cNewUserSignPayRequest.getCardHoldName());
            userInfo.setMobileNo(bankB2cNewUserSignPayRequest.getPhoneNo());
            userInfo.setCertType(bankB2cNewUserSignPayRequest.getCertType());
            userInfo.setCertNo(bankB2cNewUserSignPayRequest.getCertNo());
            userInfo.setUserStatus("00");
        } else {
            isExitUser = true;
            rglog.debug("用户存在....");
        }
        //userId放到内部节点中，签约数据入库时使用该userId
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.USER_ID, userInfo.getUserId());
        // 重置传过来的用户ID
        bankB2cNewUserSignPayRequest.setUserId(userInfo.getUserId());
        rglog.debug("创建用户完成....");

        /*检查订单可支付性*/
        rglog.debug("检查订单有效性....");
        OrderService orderService = new OrderServiceImpl();
        OrderInfo orderInfo = orderService.selectOrderInfoByUserOrderId(instId, bankB2cNewUserSignPayRequest.getUserOrderId());
        if (null == orderInfo) {
            rglog.error("订单信息不存在!");
            throw new BizException(RespCodeEnum.ORDER_NOEXIT.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }
        UserOrderInfo userOrderInfo = orderInfo.getUserOrderInfo();
        /*登记支付备注*/
        userOrderInfo.setOrderDesc(bankB2cNewUserSignPayRequest.getPayNotes());

        // 0：静态码
        // 1：动态码
        String bsnCode = LimitTypeEnum.B2C_STATIC.getLimitType();
        // 动态二维码
        if (!StringUtil.isEmptyOrNull(userOrderInfo.getOrderExtraInfo())) {
            JSONObject jsonObj = JSON.parseObject(userOrderInfo.getOrderExtraInfo());
            if (jsonObj.get("qrCodeType") != null && jsonObj.get("qrCodeType").equals("1")) {
                bsnCode = LimitTypeEnum.C2B_QR.getLimitType();
            }
        }
        rglog.debug("检查限额.......");
        String limitInst = bankB2cNewUserSignPayRequest.getHeader().getInstId() + "|" + userInfo.getUserInst() + "|" + bankB2cNewUserSignPayRequest.getUserId();
        // 校验限额
        UserPayAuthTypeEnum userPayAuthTypeEnum = userService.getUserPayAuthType(instId, bankB2cNewUserSignPayRequest.getUserId(), bankB2cNewUserSignPayRequest.getOrderAmt(), LimitTypeEnum.CASHIER.getLimitType());
        String authType = userPayAuthTypeEnum.getType();
        boolean isPay = true;
        // 02 密码+短信验证
        // 03 密码+软Ukey
        if ("03".equals(authType)) {
            rglog.error("签约时，如果限额超了短信，无法支付。");
            // 不能支付了
            isPay = false;
        }

        rglog.debug("检查短信验证码.......");
        /* 先签约后支付,校验短信验证码 */
        SmsService smsService = new SmsServiceImpl();
        smsService.verifySmsCode(bankB2cNewUserSignPayRequest.getHeader().getInstId(), SmsTypeEnum.CARD_SIGN.getSmsType(),
                bankB2cNewUserSignPayRequest.getAuthCode(), bankB2cNewUserSignPayRequest.getTransSeqNum());

        /*查询签约信息表*/
        rglog.debug("查询签约关系.......");
        SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
        List<SignAcctInfo> signAcctInfoList = signAcctInfoMapper.selectSignAcctInfoBySignTyUserId(instId,
                bankB2cNewUserSignPayRequest.getUserId(), userService.getUserSessionValue("signInst"));
        /*本行卡签约*/
        SignAcctInfo signAcctInfo = bankDebitSign(signCardInfo, bankB2cNewUserSignPayRequest, signAcctInfoList);

        if (isExitUser) {
            // 更新用户
            if (!userService.updateUserInfo(userInfo)) {
                throw new BizException(RespCodeEnum.USER_REGISTER_ERROR.getRespCode(), RespCodeEnum.USER_REGISTER_ERROR.getRespDesc());
            }
        } else {
            // 注册用户
            if (!userService.registerUserInfo(userInfo)) {
                throw new BizException(RespCodeEnum.USER_REGISTER_ERROR.getRespCode(), RespCodeEnum.USER_REGISTER_ERROR.getRespDesc());
            }
        }

        // 把最新的用户编号更新到Session缓存中
        userService.setUserSessionValue("userId", userInfo.getUserId());
        /*调用银联支付交易接口支
         * 1:校验用户限额是否超限*/
        /*根据用户订单表查询是否享受营销*/
        List<CouponInfoBean> couponInfoBeanList = null;
        /*订单金额不为空时，校验订单表中的订单金额是否与交易金额一致*/
        if (!StringUtil.isEmptyOrNull(userOrderInfo.getOrderAmt())
                && AmountUtil.compare(userOrderInfo.getOrderAmt(),
                bankB2cNewUserSignPayRequest.getOrderAmt()) != 0) {
            rglog.error("支付金额和订单金额不一致！instId:{}， orderAmt:{}, txnAmt:{}", instId,
                    userOrderInfo.getOrderAmt(),
                    bankB2cNewUserSignPayRequest.getOrderAmt());
            throw new BizException(RespCodeEnum.TRANS_AMT_DISACCORD.getRespCode(), RespCodeEnum.TRANS_AMT_DISACCORD.getRespDesc());
        }

        BizResponse bizResponse = new BizResponse();

        // 签约不支付
        if (!isPay) {
            bizResponse.setRspSysId(AppParamConstant.IGAS);
            bizResponse.setRespCode(RespCodeEnum.LIMIT_OVER_NO_PAY.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.LIMIT_OVER_NO_PAY.getRespDesc());
            return bizResponse;
        }
        /*获取手机APP银联机构号*/
        SysParamService sysParamService = new SysParamServiceImpl();
        /* 银联码，获取法人行在银联的机构号 */
        String unionPayCodeKey = "unionPayerOrgCode" + "_" + bankB2cNewUserSignPayRequest.getHeader().getChanlId();
        if (bankB2cNewUserSignPayRequest.getHeader().getChanlId().equals("A2")) {
            unionPayCodeKey = "unionPayerOrgCode" + "_" + "03";
        }
        SysParam unionPayCode = sysParamService.getSysParamInfo(instId, "OPMS_SYS_PARAM", unionPayCodeKey);
        if (null == unionPayCode) {
            rglog.error("获取二维码服务失败！获取法人行在银联的机构号失败！instId:{}", instId);
            throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
        }

        String strUnonPayCode = unionPayCode.getParamValue();

        // 查询营销
        queryCoupon(bankB2cNewUserSignPayRequest, signAcctInfo, userOrderInfo, strUnonPayCode);

        // 如果存在营销
        if (!StringUtil.isEmptyOrNull(userOrderInfo.getDiscountInfo())) {
            List<CouponInfoBean> couponInfoList = JSON.parseArray(userOrderInfo.getDiscountInfo(), CouponInfoBean.class);
            if (!couponInfoList.isEmpty()) {
                CouponInfoBean couponInfoBean = couponInfoList.get(0);
                couponInfoBeanList = new ArrayList<>();
                // 只向银联传送第一条优惠
                couponInfoBeanList.add(couponInfoBean);
            }
        }

        B2COrderPayRequest b2COrderPayRequest = new B2COrderPayRequest();
        /*银联机构号*/
        b2COrderPayRequest.setIssInsCode(strUnonPayCode);
        /*订单金额	orderAmt*/
        b2COrderPayRequest.setOrderAmt(userOrderInfo.getRealPayAmt());
        /*交易币种*/
        b2COrderPayRequest.setOrderCcy(userOrderInfo.getOrderCcy());
        /* 交易顺序号txnNo*/
        b2COrderPayRequest.setTxnNo(userOrderInfo.getSysSeqNum());
        /*付款方信息payerInfo*/
        PayerInfo payerInfo = new PayerInfo();
        /*新卡签约支付只能是本行卡*/
        payerInfo.setAccNo(bankB2cNewUserSignPayRequest.getAcctNo());
        // card_hold_name
        payerInfo.setName(bankB2cNewUserSignPayRequest.getCardHoldName());
        /*贷记卡判断 01-本行贷记账户,11-他行贷记账户*/
        if ("01".equals(bankB2cNewUserSignPayRequest.getCardType())) {
            payerInfo.setCardAttr("02"); // 贷记卡
        } else {
            payerInfo.setCardAttr("01"); // 借记卡
        }
        /*预留手机号*/
        payerInfo.setMobile(signAcctInfo.getReserveMobileNo());
        b2COrderPayRequest.setPayerInfo(payerInfo);
        /*风控信息riskInfo*/
        RiskInfoBean riskInfo = new RiskInfoBean();
        RiskInfo webRiskInfo = bankB2cNewUserSignPayRequest.getRiskInfo();
        if (StringUtil.isEmptyOrNull(webRiskInfo.getDevId())) {
            riskInfo.setDeviceID("DevId");
        } else {
            riskInfo.setDeviceID(webRiskInfo.getDevId());
        }
        if (StringUtil.isEmptyOrNull(webRiskInfo.getDeviceMode())) {
            riskInfo.setDeviceName("DeviceMode");
        } else {
            riskInfo.setDeviceName(webRiskInfo.getDeviceMode());
        }
        if (StringUtil.isEmptyOrNull(webRiskInfo.getTermIp())) {
            riskInfo.setSourceIP("127.0.0.1");
        } else {
            riskInfo.setSourceIP(webRiskInfo.getTermIp());
        }
        riskInfo.setDeviceLocation(webRiskInfo.getDeviceLocation());
        if (StringUtil.isEmptyOrNull(webRiskInfo.getDeviceMode())) {
            riskInfo.setDeviceType("DeviceType");
        } else {
            riskInfo.setDeviceType(webRiskInfo.getDeviceMode());
        }
        //应用提供方账户ID
        if (!StringUtil.isEmptyOrNull(signAcctInfo.getUserId())) {
            riskInfo.setAccountIdHash(MD5Util.MD5Encode(signAcctInfo.getUserId()));
        }
        //银行预留手机号
        if (!StringUtil.isEmptyOrNull(signAcctInfo.getReserveMobileNo())) {
            riskInfo.setMobile(signAcctInfo.getReserveMobileNo());
        }
        //账户注册日期  8 位日期字符 yyyymmdd
        if (!StringUtil.isEmptyOrNull(signAcctInfo.getCreateTime())) {
            riskInfo.setUsrRgstrDt(DateUtil.dateStringFormatConvert(signAcctInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss.SSS", "yyyyMMdd"));
        }
        b2COrderPayRequest.setRiskInfoBean(riskInfo);
        /*使用优惠卷*/
        if (couponInfoBeanList != null) {
            /* 初始交易金额 */
            b2COrderPayRequest.setOrigTxnAmt(userOrderInfo.getOrderAmt());
            /*银联返回的优惠信息*/
            b2COrderPayRequest.setCouponInfoList(couponInfoBeanList);
        }
        cc.rengu.igas.channel.upqc.facade.base.Header upHeader = new cc.rengu.igas.channel.upqc.facade.base.Header();
        BeanUtil.beanCopy(bankB2cNewUserSignPayRequest.getHeader(), upHeader);
        /*付款交易*/
        upHeader.setTxnNum("0130000903");
        upHeader.setSrcSysId("OPMS");
        b2COrderPayRequest.setHeader(upHeader);
        b2COrderPayRequest.setOrderType(userOrderInfo.getOrderType());
        /* 实际支付金额*/
        b2COrderPayRequest.setOrderAmt(userOrderInfo.getRealPayAmt());
        rglog.debug("打印银联主扫付款请求报文<{}>", JSON.toJSONString(b2COrderPayRequest));

        /* 调用银联付款*/
        DubboService dubboService = new DubboServiceImpl();
        Result<B2COrderPayResponse> responseResult = (Result<B2COrderPayResponse>) dubboService.callDubboService("upqcPayerService",
                "b2cOrderPay", b2COrderPayRequest);
        if (null == responseResult) {
            rglog.error("调用银联主扫二维码付款，订单号<{}>信息失败,iReturnCode:<{}>",
                    bankB2cNewUserSignPayRequest.getUserOrderId(),
                    responseResult.getResult().getRespCode());
        } else {
            B2COrderPayResponse orderPayResponse = responseResult.getResult();
            rglog.debug("银联返回相应码<{}>,相应信息<{}>", orderPayResponse.getRespCode(), orderPayResponse.getRespDesc());
            if ("04".equals(orderPayResponse.getRespCode())) {
                /*订单处理中*/
                rglog.debug("银联返回交易处理中");
                userOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                userOrderInfo.setOrderStatus(OrderStatusEnum.INIT.getStatus());
                userOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
                bizResponse.setRespCode(orderPayResponse.getRespCode());
                bizResponse.setRespDesc(orderPayResponse.getRespDesc());
            } else if (!"00000000".equals(orderPayResponse.getRespCode())) {
                /*更新为失败*/
                userOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                userOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                rglog.error("支付失败，sysSeqNum:<{}>, dubboRespCode:<{}> !", userOrderInfo.getSysSeqNum(), orderPayResponse.getRespCode());
                bizResponse.setRespCode(orderPayResponse.getRespCode());
                bizResponse.setRespDesc(orderPayResponse.getRespDesc());
            } else {
                // 支付成功
                userOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                userOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
                userOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                /*付款信息*/
                userOrderInfo.setFrontSeqNum(orderPayResponse.getVoucherNum());
                /*用户编号*/
                userOrderInfo.setUserId(signAcctInfo.getUserId());
                /*累计用户限额*/
                /*累计用户限额*/
                userService.updateUserTransLimit(userOrderInfo.getInstId(),
                        signAcctInfo.getUserId(),
                        txnInfo.getSrcTxnAuthCfg().getTxnNum(),
                        userOrderInfo.getRealPayAmt());

                bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
                bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            }
        }

        //增加付款人信息
        JSONObject josnObj = new JSONObject();
        if (!StringUtil.isEmptyOrNull(userOrderInfo.getOrderExtraInfo())) {
            josnObj = JSON.parseObject(userOrderInfo.getOrderExtraInfo());
        }
        if (AcctTypeEnum.BANK_CREDIT.getAcctType().equals(signAcctInfo.getSignAcctType())
                || AcctTypeEnum.BANK_DEBIT.getAcctType().equals(signAcctInfo.getSignAcctType())) {
            josnObj.put("payType", PayTypeEnum.BANK_CARD.getPayType());
        } else if (AcctTypeEnum.OTHER_CREDIT.getAcctType().equals(signAcctInfo.getSignAcctType())
                || AcctTypeEnum.OTHER_DEBIT.getAcctType().equals(signAcctInfo.getSignAcctType())) {
            josnObj.put("payType", PayTypeEnum.OTHER_BANK_CARD.getPayType());
        }
        josnObj.put("payerAcctInfo", signAcctInfo.getSignAcctNo());
        josnObj.put("payerAcctName", signAcctInfo.getCardHoldName());
        josnObj.put("payerAcctType", signAcctInfo.getSignAcctType());
        josnObj.put("transFlag", "0");//支付
        userOrderInfo.setOrderExtraInfo(JSON.toJSONString(josnObj));

        /*更新状态*/
        boolean isOrderCode = orderService.updateOrderInfo(userOrderInfo, null, null);
        if (!isOrderCode) {
            rglog.error("更新用户订单表失败!");
            throw new BizException(RespCodeEnum.UPDATE_ORDER_ERROR.getRespCode(), RespCodeEnum.ORDER_NOEXIT.getRespDesc());
        }

        BankB2cNewUserSignPayResponse bankB2cNewUserSignPayResponse = new BankB2cNewUserSignPayResponse();
        // 实际支付金额
        bankB2cNewUserSignPayResponse.setActualAmt(userOrderInfo.getRealPayAmt());
        // 优惠金额
        bankB2cNewUserSignPayResponse.setDiscountAmt(userOrderInfo.getRealDiscountAmt());
        // 订单金额
        bankB2cNewUserSignPayResponse.setOrderAmt(userOrderInfo.getOrderAmt());
        // 存在优惠
        if (couponInfoBeanList != null && couponInfoBeanList.size() != 0) {
            CouponInfo opmscoupBean = new CouponInfo();
            BeanUtil.beanCopy(couponInfoBeanList.get(0), opmscoupBean);
            bankB2cNewUserSignPayResponse.setCouponInfo(opmscoupBean);
        }
        // 用户编号
        bankB2cNewUserSignPayResponse.setUserId(userInfo.getUserId());
        bizResponse.setResult(bankB2cNewUserSignPayResponse);
        bizResponse.setRspSysId(AppParamConstant.IGAS);
        return bizResponse;
    }

    @Override
    protected void afterBizProcess(BizResponse response) throws Exception {
        BankB2cNewUserSignPayResponse bankB2cNewUserSignPayResponse = (BankB2cNewUserSignPayResponse) response.getResult();
        ConvertUtil.convertInput(bankB2cNewUserSignPayResponse);
    }

    @Override
    protected RiskMonitorInfo getRiskMonitorInfo() {
        return null;
    }

    /**
     * 查询营销，确认银联是否有优惠
     */
    private void queryCoupon(BankB2cNewUserSignPayRequest bankB2cNewUserSignPayRequest,
                             SignAcctInfo signAcctInfo,
                             UserOrderInfo userOrderInfo,
                             String strUnonPayCode) throws Exception {
        rglog.debug("开始查询银联营销{}", userOrderInfo.getSysSeqNum());
        B2CQueryCouponRequest b2CQueryCouponRequest = new B2CQueryCouponRequest();

        PayerInfo payerInfo = new PayerInfo();

        // 付款人员信息
        // 本他行判断
        if ("0".equals(signAcctInfo.getSignAcctType().substring(0, 1))) {
            payerInfo.setAccNo(signAcctInfo.getSignAcctNo());
        } else {
            // 他行使用TOKEN
            payerInfo.setAccNo(signAcctInfo.getSignToken());
        }
        // card_hold_name
        payerInfo.setName(signAcctInfo.getCardHoldName());
        // 签约银行名称
        //payerInfo.setPayerBankInfo(signAcctInfo.getSignBankName());
        // 贷记卡判断
        // 01-本行贷记账户
        // 11-他行贷记账户
        if ("01".equals(signAcctInfo.getSignAcctType()) || "11".equals(signAcctInfo.getSignAcctType())) {
            payerInfo.setCardAttr("02"); // 贷记卡
        } else {
            payerInfo.setCardAttr("01"); // 借记卡
        }
        // 预留手机号
        payerInfo.setMobile(signAcctInfo.getReserveMobileNo());
        b2CQueryCouponRequest.setPayerInfo(payerInfo);

        // 银联机构号
        b2CQueryCouponRequest.setIssInsCode(strUnonPayCode);
        // 订单金额	orderAmt --与页面交互，无需除以100
        b2CQueryCouponRequest.setOrderAmt(bankB2cNewUserSignPayRequest.getOrderAmt());
        //交易顺序号	txnNo
        b2CQueryCouponRequest.setTxnNo(userOrderInfo.getSysSeqNum());

        // 收款方信息	payeeInfoBean
        PayeeInfoBean payeeInfoBean = JSON.parseObject(userOrderInfo.getRemark2(), PayeeInfoBean.class);
        b2CQueryCouponRequest.setPayeeInfoBean(payeeInfoBean);

        //风控信息	riskInfo
        RiskInfoBean riskInfo = new RiskInfoBean();
        RiskInfo webRiskInfo = bankB2cNewUserSignPayRequest.getRiskInfo();
        riskInfo.setDeviceID(webRiskInfo.getDevId());
        riskInfo.setDeviceName(webRiskInfo.getDeviceMode());
        riskInfo.setSourceIP(webRiskInfo.getTermIp());
        riskInfo.setDeviceLocation(webRiskInfo.getDeviceLocation());
        riskInfo.setDeviceType(webRiskInfo.getDeviceMode());
        //风控信息	riskInfo
        if (StringUtil.isEmptyOrNull(webRiskInfo.getDevId())) {
            riskInfo.setDeviceID("DevId");
        } else {
            riskInfo.setDeviceID(webRiskInfo.getDevId());
        }
        if (StringUtil.isEmptyOrNull(webRiskInfo.getDeviceMode())) {
            riskInfo.setDeviceName("DeviceMode");
        } else {
            riskInfo.setDeviceName(webRiskInfo.getDeviceMode());
        }
        if (StringUtil.isEmptyOrNull(webRiskInfo.getTermIp())) {
            riskInfo.setSourceIP("127.0.0.1");
        } else {
            riskInfo.setSourceIP(webRiskInfo.getTermIp());
        }
        riskInfo.setDeviceLocation(webRiskInfo.getDeviceLocation());
        if (StringUtil.isEmptyOrNull(webRiskInfo.getDeviceMode())) {
            riskInfo.setDeviceType("DeviceType");
        } else {
            riskInfo.setDeviceType(webRiskInfo.getDeviceMode());
        }
        //应用提供方账户ID
        if (!StringUtil.isEmptyOrNull(signAcctInfo.getUserId())) {
            riskInfo.setAccountIdHash(MD5Util.MD5Encode(signAcctInfo.getUserId()));
        }
        //银行预留手机号
        if (!StringUtil.isEmptyOrNull(signAcctInfo.getReserveMobileNo())) {
            riskInfo.setMobile(signAcctInfo.getReserveMobileNo());
        }
        //账户注册日期  8 位日期字符 yyyymmdd
        if (!StringUtil.isEmptyOrNull(signAcctInfo.getCreateTime())) {
            riskInfo.setUsrRgstrDt(DateUtil.dateStringFormatConvert(signAcctInfo.getCreateTime(), "yyyy-MM-dd HH:mm:ss.SSS", "yyyyMMdd"));
        }
        b2CQueryCouponRequest.setRiskInfo(riskInfo);

        cc.rengu.igas.channel.upqc.facade.base.Header upHeader = new cc.rengu.igas.channel.upqc.facade.base.Header();
        BeanUtil.beanCopy(bankB2cNewUserSignPayRequest.getHeader(), upHeader);
        upHeader.setTxnNum("0180000903");// 查询营销
        upHeader.setSrcSysId("OPMS");
        b2CQueryCouponRequest.setHeader(upHeader);
        b2CQueryCouponRequest.setOrderCcy("156");
        // 查询营销
        DubboService dubboService = new DubboServiceImpl();
        Result<B2CQueryCouponResponse> responseResult = (Result<B2CQueryCouponResponse>) dubboService.callDubboService("upqcPayerService", "b2cQueryCoupon", b2CQueryCouponRequest);

        // 计算优惠金额
        String couponAmt = "0";
        List<CouponInfo> couponInfoList = new ArrayList<CouponInfo>();
        if (null != responseResult.getResult().getCouponInfoList()
                && responseResult.getResult().getCouponInfoList().size() != 0) {
            for (CouponInfoBean couponInfoBean : responseResult.getResult().getCouponInfoList()) {
                // 优惠累加
                couponAmt = AmountUtil.addition(couponAmt, couponInfoBean.getOffstAmt());
                // 复制Bean
                CouponInfo reCouBean = new CouponInfo();
                BeanUtil.beanCopy(couponInfoBean, reCouBean);
                couponInfoList.add(reCouBean);
            }
        }

        // 没有金额模式
        if (StringUtil.isEmptyOrNull(userOrderInfo.getOrderAmt())) {
            // 交易金额
            userOrderInfo.setOrderAmt(bankB2cNewUserSignPayRequest.getOrderAmt());
        }
        // 实际支付金额
        userOrderInfo.setRealPayAmt(AmountUtil.subtraction(userOrderInfo.getOrderAmt(), couponAmt));
        // 实际优惠总金额
        userOrderInfo.setRealDiscountAmt(couponAmt);
        // 有优惠
        if (responseResult.getResult().getCouponInfoList() != null) {
            // 优惠信息列表
            userOrderInfo.setDiscountInfo(JSON.toJSONString(responseResult.getResult().getCouponInfoList()));
        }
    }

    /**
     * 本行借记卡快捷签约
     *
     * @param cardBinInfo                  卡BIN
     * @param bankB2cNewUserSignPayRequest 新卡签约请求体
     * @param signAcctInfoList             用户签约集合
     * @return 签约信息
     * @throws Exception 异常
     */
    private SignAcctInfo bankDebitSign(SignCardInfoBean cardBinInfo,
                                       BankB2cNewUserSignPayRequest bankB2cNewUserSignPayRequest,
                                       List<SignAcctInfo> signAcctInfoList) throws Exception {

        /*获取通道服务调用配置*/
        PublicDealService publicDealService = new PublicDealServiceImpl();
        /*请求报文获取值赋值*/
        String instId = bankB2cNewUserSignPayRequest.getHeader().getInstId();
        String acctNo = bankB2cNewUserSignPayRequest.getAcctNo();
        String certNo = bankB2cNewUserSignPayRequest.getCertNo();
        String certType = bankB2cNewUserSignPayRequest.getCertType();
        String custName = bankB2cNewUserSignPayRequest.getCardHoldName();
        String mobilePhone = bankB2cNewUserSignPayRequest.getPhoneNo();
        /*本行卡四要素验证*/
        publicDealService.bankFourEleVerify(instId, acctNo, certNo, certType, mobilePhone, custName);
        /*检查卡片是否开通通知*/
        /*机构选择需要校验核心动帐开通短信接口时才调用该不操作，默认都需要校验
        本行借机卡签约是否需要校验 核心动帐开通的短信接口*/
        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParamInfo = sysParamService.getSysParamInfo(bankB2cNewUserSignPayRequest.getHeader().getInstId(),
                CopsParamConstant.OPMS_SYS_PARAM, "NEED_CHECK_SMS_NOTIFY");
        if (null == sysParamInfo || AppParamConstant.NO.equals(sysParamInfo.getParamStatus()) || !AppParamConstant.YES.equals(sysParamInfo.getParamValue())) {
            rglog.debug("该机构用户签约不需要校验用户是否开通核心动帐开通短信，instId:<{}>", bankB2cNewUserSignPayRequest.getHeader().getInstId());
        } else {
            rglog.debug("该机构用户签约需要校验用户是否开通核心动帐开通短信，instId:<{}>", bankB2cNewUserSignPayRequest.getHeader().getInstId());
            publicDealService.checkSmsSignNotify(instId, acctNo, certNo, certType, mobilePhone);
        }
        /*借记卡签约*/
        UserService userService = new UserServiceImpl();
        publicDealService.debitCardCoreSign(instId, acctNo, certNo, certType, userService.getUserSessionValue("signInst"), custName);
        /*签约signToken*/
        String signToken = cardBinInfo.getBankBranchCode().trim() + "|" + DateUtil.getCurrentTimeStamp() + RandomUtil.getRandomInt();
        rglog.debug("生成签约token<{}>", signToken);
        /*支付序号*/
        int payIndex = CopsParamConstant.INT_ZERO;
        List<SignAcctInfo> collect = signAcctInfoList.stream().filter(item -> item.getSignStatus().equals(AppParamConstant.YES)).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            collect = collect.stream().sorted(Comparator.comparing(SignAcctInfo::getPayIndex).reversed()).collect(Collectors.toList());
            payIndex = collect.get(0).getPayIndex() + 1;
        }
        /*判断当前账号是否已经存在*/
        List<SignAcctInfo> collect1 = signAcctInfoList.stream().filter(item -> item.getSignAcctNo().equals(bankB2cNewUserSignPayRequest.getAcctNo())
                && SignTokenTypeEnum.BANK_QUICK_PAY.getSignTypeCode().equals(item.getSignTokenType())).collect(Collectors.toList());
        /*当前账号不存在或状态为解约*/
        SignAcctInfo signAcctInfo = null;
        if (!collect1.isEmpty() && AppParamConstant.NO.equals(collect1.get(CopsParamConstant.INT_ZERO).getSignStatus())) {
            rglog.debug("用户:<{}>当前卡:<{}>在当前signInst:<{}>做签约,签约状态为解约",
                    bankB2cNewUserSignPayRequest.getUserId(),
                    bankB2cNewUserSignPayRequest.getAcctNo(), userService.getUserSessionValue("signInst"));
            signAcctInfo = updateSignAcctInfo(collect1.get(0), signToken, payIndex, bankB2cNewUserSignPayRequest);
        } else {
            rglog.debug("用户:<{}>当前卡:<{}>未在当前signInst:<{}>做签约",
                    bankB2cNewUserSignPayRequest.getUserId(),
                    bankB2cNewUserSignPayRequest.getAcctNo(), userService.getUserSessionValue("signInst"));
            signAcctInfo = registerSignAcctInfo(userService.getUserSessionValue("signType"), userService.getUserSessionValue("signInst"), signToken, payIndex, cardBinInfo.getBankBranchCode(),
                    cardBinInfo.getBankName(), SignTokenTypeEnum.BANK_QUICK_PAY.getSignTypeCode(),
                    cardBinInfo.getAcctType(), bankB2cNewUserSignPayRequest);
        }
        return signAcctInfo;
    }

    /**
     * 更新原签约信息未已签约
     *
     * @param oriSignAcctInfo              原签约信息
     * @param signNo                       签约token
     * @param payIndex                     支付序号
     * @param BankB2cNewUserSignPayRequest 新卡签约请求体
     * @return 签约信息
     * @throws Exception 异常
     */
    private SignAcctInfo updateSignAcctInfo(SignAcctInfo oriSignAcctInfo, String signNo, int payIndex, BankB2cNewUserSignPayRequest BankB2cNewUserSignPayRequest) throws Exception {
        /*更新已签约的信息*/
        rglog.debug("更新已签约的信息");
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
        oriSignAcctInfo.setSignToken(signNo);
        oriSignAcctInfo.setPayIndex(payIndex);
        oriSignAcctInfo.setReserveMobileNo(BankB2cNewUserSignPayRequest.getPhoneNo());
        oriSignAcctInfo.setSignDate(DateUtil.getCurrentDate());
        oriSignAcctInfo.setSignSysSeqNum(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
        oriSignAcctInfo.setSignExpiryDate("20991231");
        oriSignAcctInfo.setSignStatus(AppParamConstant.YES);
        oriSignAcctInfo.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        rglog.debug("打印签约信息<{}>", JSON.toJSONString(oriSignAcctInfo));
        int iReturnCode = signAcctInfoMapper.updateSignAcctInfoBySignAcctNo(oriSignAcctInfo);
        if (iReturnCode != 0) {
            rglog.debug("更新签约信息失败");
            throw new BizException(RespCodeEnum.UPDATE_SIGN_ACCT_ERROR.getRespCode(), RespCodeEnum.UPDATE_SIGN_ACCT_ERROR.getRespDesc());
        }
        return oriSignAcctInfo;
    }

    /**
     * 登记签约信息表
     *
     * @param signNo        协议号
     * @param bankNo        签约账户联行号
     * @param signTokenType 签约标记类型
     */
    private SignAcctInfo registerSignAcctInfo(String signType, String signInst, String signNo, int payIndex, String bankNo, String bankName,
                                              String signTokenType, String acctType, BankB2cNewUserSignPayRequest BankB2cNewUserSignPayRequest) throws Exception {
        SignAcctInfoMapper signAcctInfoMapper = new SignAcctInfoMapperImpl();
        rglog.debug("登记签约信息");
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        SignAcctInfo signAcctInfo = new SignAcctInfo();
        ConvertUtil.convertOutput(signAcctInfo);
        signAcctInfo.setSignToken(signNo);
        signAcctInfo.setSignTokenType(signTokenType);
        signAcctInfo.setSignType(signType);
        signAcctInfo.setSignInst(signInst);
        signAcctInfo.setSignAcctType(acctType);
        signAcctInfo.setPayIndex(payIndex);
        signAcctInfo.setSignAcctNo(BankB2cNewUserSignPayRequest.getAcctNo());
        signAcctInfo.setReserveMobileNo(BankB2cNewUserSignPayRequest.getPhoneNo());
        signAcctInfo.setSignBankNo(bankNo);
        signAcctInfo.setSignBankName(bankName);
        signAcctInfo.setSignDate(DateUtil.getCurrentDate());
        signAcctInfo.setSignSysSeqNum(xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM));
        signAcctInfo.setSignExpiryDate("20991231");
        signAcctInfo.setSignStatus(AppParamConstant.YES);
        signAcctInfo.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        rglog.debug("打印签约信息<{}>", JSON.toJSONString(signAcctInfo));
        int iReturnCode = signAcctInfoMapper.insertSignAcctInfo(signAcctInfo);
        if (iReturnCode != 0) {
            rglog.debug("插入签约信息失败");
            throw new BizException(RespCodeEnum.USER_REGISTER_ERROR.getRespCode(), RespCodeEnum.USER_REGISTER_ERROR.getRespDesc());
        }
        return signAcctInfo;
    }

    @Override
    public ChannelCallCfg channelCallSceneDiscern(Object request, List<ChannelCallCfg> channelCallCfgList) throws Exception {
        return null;
    }

    @Override
    public CheckResultEnum channelCallPreCheck(Object request, ChannelCallCfg channelCallCfg, OrderInfo orderInfo) throws Exception {
        return null;
    }

    @Override
    public TransStatusEnum channelCallResultProc(Object request, ChannelCallCfg channelCallCfg, TransStatusEnum transStatusEnum, Object channelResponse, OrderInfo needUpdateOrderInfo) throws Exception {
        return null;
    }
}
